//事件总线(非常常用的功能)
//对比下 Vue 中事件总线的实现
class EventEmitter{
    constructor(){
        this.cache = {};
    }

    //绑定事件
    on(name, fn){
        //数组的形式存储事件
        if(this.cache[name]){
            this.cache[name].push(fn);
        }else{
            this.cache[name] = [fn];
        }
    }

    //解绑事件
    off(name, fn){
        if(fn){
            var tasks = this.cache[name];
            if(tasks){
                //找到方法所在的索引
                var idx = tasks.findIndex(f=>{ return f===fn; });
                tasks.splice(idx,1);
            }
        }else{
            //全部解绑
            delete this.cache[name];
        }
    }

    //触发事件
    emit(name){  //不传数据吗？
        if(this.cache[name]){
            //创建副本，避免函数执行过程中，又有事件入栈，引发不必要的问题
            let tasks = this.cache[name].slice();
            var args = [...arguments].slice(1);
            for(let fn of tasks){
                if(args) fn(...args);
                else fn();
            }
        }
    }

    once(name,fn){  //添加监听一次就删除的事件
        var on = ()=>{
            fn();
            this.off(name,on);
        }
        this.on(name, on);
    }
}

var eventBus = new EventEmitter();
var task1 = ()=>{
    console.log("task1");
}
var task2 = ()=>{
    console.log("task2");
}
var task3 = ()=>{
    console.log("task3");
}

eventBus.on("task", task1);
eventBus.on("task", task2);
//只会执行一次的 task3
eventBus.once("task", task3);

nextTick(()=>{
    eventBus.emit("task");
    nextTick(()=>{
        eventBus.emit("task");
    })
})

function nextTick(cb){
    setTimeout(()=>{ cb && cb(); },2000)
}

